# -*- coding: utf-8 -*-
# This code written by ChanGOGOGO
"""
拨打数据分析(蚂蚁)
"""
import pymysql
from util import (
    read_config,
    logging,
    data2beautify,
    query_es,
    ms2min,
    calc_percent,
    write_excel,
    db_ip,
    db_port,
    db_username,
    db_password,
    es_ip,
    es_port,
    excel_save_dir,
)


class ExportAntDataAnalysis:
    def __init__(self, ui_data):
        self.data_date = ui_data["data_date"]
        self.business = ui_data.get("business")
        self.data_type = ui_data.get("data_type")
        self.call_type = ui_data.get("call_type")
        self.start_time = ui_data.get("start_time")
        self.end_time = ui_data.get("end_time")
        self.task_ids = ui_data.get("target_datas")
        company_id = ui_data.get("company_id")
        self.db_name = f"yicall_{company_id}"
        self.table_index = ui_data.get("business_id")
        self.conn = pymysql.connect(
            host=db_ip,
            port=db_port,
            user=db_username,
            passwd=db_password,
            charset="utf8",
        )
        self.cursor = self.conn.cursor()
        ant_config = read_config(r"./config/ant.yaml")
        self.prologue_hangup_nodes = ant_config.get("开场白阶段挂断")
        self.retention_phase_hangup_nodes = ant_config.get("挽留阶段挂断")
        self.bootstrap_phase_main_hangup_nodes = ant_config.get("引导阶段(主流程)挂断")
        self.bootstrap_phase_detainment_hangup_nodes = ant_config.get(
            "引导阶段(挽留)挂断"
        )
        self.success_hangup_nodes = ant_config.get("成功阶段挂断")
        self.task_info = self.query_task_info()
        self.close_db()

    def query_task_info(self):
        """查询任务信息"""
        sql = f"""select task_id,task_name from {self.db_name}.b_{self.table_index}_callout_task;"""
        logging.info(f"查询{self.business}任务信息SQL:\n{sql}")
        self.cursor.execute(sql)
        result = self.cursor.fetchall()
        task_info = dict()
        if result:
            task_info = {task_id: task_name for task_id, task_name in result}
        logging.info(f"获取到{self.business}下的任务信息：\n{data2beautify(task_info)}")
        return task_info

    def close_db(self):
        self.cursor.close()
        self.conn.close()

    def query_es_data(self):
        """查询呼出通话记录信息"""
        es_index = (
            f"{self.db_name}_{self.table_index}_callout_session_ach_{self.data_date}"
        )
        body = {
            "query": {
                "bool": {
                    "must": [
                        {
                            "range": {
                                "calloutFinishTime": {
                                    "gte": self.start_time,
                                    "lte": self.end_time,
                                }
                            }
                        }
                    ]
                }
            }
        }
        fields = [
            "calloutFinishTime",
            "taskId",
            "calloutConnectStatus",
            "sessionAnalyseInfo",
            "calloutTimes",
            "dialogDuration",
            "detailInfo",
            "calloutLastNodeName",
        ]
        es_data = query_es(es_index, body, fields, es_ip, es_port)
        total_data = len(es_data)
        logging.info(f"从{es_index}中共查询出{total_data}条数据。")
        return es_data

    def analysis_task_call_data(self):
        """"""
        es_data = self.query_es_data()
        task_call_data = dict()
        for x in es_data:
            callout_date = x.get("calloutFinishTime")[:10]
            task_id = int(x.get("taskId"))
            task_name = self.task_info.get(task_id)
            session_analyse_info = x.get("sessionAnalyseInfo")
            if session_analyse_info is None:
                continue
            callout_connect_status = x.get("calloutConnectStatus")
            intent = session_analyse_info.get("dialogUserPrefer")
            callout_times = int(x.get("calloutTimes"))
            dialog_duration_ms = int(x.get("dialogDuration"))
            detail_info = x.get("detailInfo")
            import_time = detail_info.get("importTime")
            # 页面导入的手机号没有导入时间（不参与统计），只有接口导入的手机号才有导入时间。
            if import_time:
                import_time = import_time[:10]
            else:
                continue
            hangup_node_name = x.get("calloutLastNodeName")
            # 根据callout_times(第几次外呼)来判定数据属于哪个重呼策略，且只有首轮拨打的数据计做蚂蚁推送量
            if callout_times == 0:
                recall_strategy = "未拨打"
                ant_push_num = 1
            elif callout_times == 1:
                recall_strategy = "T"
                ant_push_num = 1
            else:
                recall_strategy = f"T+{callout_times - 1}"
                ant_push_num = 0
            # 输出意向中包含A或B，就认为有意向
            if intent:  # 有些场景没有配置客户意向
                if intent.upper().find("A") != -1:
                    a_intent_num = 1
                    b_intent_num = 0
                elif intent.upper().find("B") != -1:
                    a_intent_num = 0
                    b_intent_num = 1
                else:
                    a_intent_num = 0
                    b_intent_num = 0
            else:
                a_intent_num = 0
                b_intent_num = 0
            if callout_connect_status == "100":  # 接通才累计接通数和计算通话分钟
                connected_num = 1
                dialog_duration_min = ms2min(dialog_duration_ms)
            else:
                connected_num = 0
                dialog_duration_min = 0
            # 分析节点挂断数据
            prologue_num = 0
            retention_phase_num = 0
            bootstrap_phase_main_num = 0
            bootstrap_phase_detainment_num = 0
            success_num = 0
            if hangup_node_name in self.prologue_hangup_nodes:  # 开场白阶段挂断
                prologue_num = 1
            elif hangup_node_name in self.retention_phase_hangup_nodes:  # 挽留阶段挂断
                retention_phase_num = 1
            elif (
                hangup_node_name in self.bootstrap_phase_main_hangup_nodes
            ):  # 引导阶段(主流程)挂断
                bootstrap_phase_main_num = 1
            elif (
                hangup_node_name in self.bootstrap_phase_detainment_hangup_nodes
            ):  # 引导阶段(挽留)挂断
                bootstrap_phase_detainment_num = 1
            elif hangup_node_name in self.success_hangup_nodes:  # 走到成功节点挂断
                success_num = 1
            find_task = task_call_data.get(task_name, -1)  # 查找任务是否存在
            if find_task == -1:
                task_call_data[task_name] = {
                    import_time: {
                        callout_date: {
                            recall_strategy: {
                                "task_id": task_id,
                                "ant_push_total": ant_push_num,  # 蚂蚁推送量
                                "callout_total": 1,  # 外呼量
                                "connected_total": connected_num,  # 接通数
                                "duration_total": dialog_duration_min,  # 通话分钟数
                                "a_intent_total": a_intent_num,  # a意向数
                                "b_intent_total": b_intent_num,  # b意向数
                                "prologue_total": prologue_num,  # 开场白阶段挂断总数
                                "retention_phase_total": retention_phase_num,  # 挽留阶段挂断总数
                                "bootstrap_phase_main_total": bootstrap_phase_main_num,  # 引导阶段(主流程)挂断
                                "bootstrap_phase_detainment_total": bootstrap_phase_detainment_num,
                                # 引导阶段(挽留)挂断
                                "success_total": success_num,  # 走到成功节点挂断总数
                            }
                        }
                    }
                }
            else:
                find_import_time = task_call_data.get(task_name).get(
                    import_time, -1
                )  # 查找任务下同一天导入的数据是否存在
                if find_import_time == -1:
                    task_call_data[task_name][import_time] = {
                        callout_date: {
                            recall_strategy: {
                                "task_id": task_id,
                                "ant_push_total": ant_push_num,  # 蚂蚁推送量
                                "callout_total": 1,  # 外呼量
                                "connected_total": connected_num,  # 接通数
                                "duration_total": dialog_duration_min,  # 通话分钟数
                                "a_intent_total": a_intent_num,  # a意向数
                                "b_intent_total": b_intent_num,  # b意向数
                                "prologue_total": prologue_num,  # 开场白阶段挂断总数
                                "retention_phase_total": retention_phase_num,  # 挽留阶段挂断总数
                                "bootstrap_phase_main_total": bootstrap_phase_main_num,  # 引导阶段(主流程)挂断
                                "bootstrap_phase_detainment_total": bootstrap_phase_detainment_num,
                                # 引导阶段(挽留)挂断
                                "success_total": success_num,  # 走到成功节点挂断总数
                            }
                        }
                    }
                else:
                    # 查找任务批次下拨打日期是否存在
                    find_callout_date = (
                        task_call_data.get(task_name)
                        .get(import_time)
                        .get(callout_date, -1)
                    )
                    if find_callout_date == -1:
                        task_call_data[task_name][import_time][callout_date] = {
                            recall_strategy: {
                                "task_id": task_id,
                                "ant_push_total": ant_push_num,  # 蚂蚁推送量
                                "callout_total": 1,  # 外呼量
                                "connected_total": connected_num,  # 接通数
                                "duration_total": dialog_duration_min,  # 通话分钟数
                                "a_intent_total": a_intent_num,  # a意向数
                                "b_intent_total": b_intent_num,  # b意向数
                                "prologue_total": prologue_num,  # 开场白阶段挂断总数
                                "retention_phase_total": retention_phase_num,  # 挽留阶段挂断总数
                                "bootstrap_phase_main_total": bootstrap_phase_main_num,  # 引导阶段(主流程)挂断
                                "bootstrap_phase_detainment_total": bootstrap_phase_detainment_num,
                                # 引导阶段(挽留)挂断
                                "success_total": success_num,  # 走到成功节点挂断总数
                            }
                        }
                    else:
                        find_recall_strategy = (
                            task_call_data.get(task_name)
                            .get(import_time)
                            .get(callout_date)
                            .get(recall_strategy, -1)
                        )
                        if find_recall_strategy == -1:
                            task_call_data[task_name][import_time][callout_date][
                                recall_strategy
                            ] = {
                                "task_id": task_id,
                                "ant_push_total": ant_push_num,  # 蚂蚁推送量
                                "callout_total": 1,  # 外呼量
                                "connected_total": connected_num,  # 接通数
                                "duration_total": dialog_duration_min,  # 通话分钟数
                                "a_intent_total": a_intent_num,  # a意向数
                                "b_intent_total": b_intent_num,  # b意向数
                                "prologue_total": prologue_num,  # 开场白阶段挂断总数
                                "retention_phase_total": retention_phase_num,  # 挽留阶段挂断总数
                                "bootstrap_phase_main_total": bootstrap_phase_main_num,  # 引导阶段(主流程)挂断
                                "bootstrap_phase_detainment_total": bootstrap_phase_detainment_num,
                                # 引导阶段(挽留)挂断
                                "success_total": success_num,  # 走到成功节点挂断总数
                            }
                        else:
                            task_call_data[task_name][import_time][callout_date][
                                recall_strategy
                            ][
                                "ant_push_total"
                            ] += ant_push_num  # 蚂蚁推送量+1
                            task_call_data[task_name][import_time][callout_date][
                                recall_strategy
                            ][
                                "callout_total"
                            ] += 1  # 外呼量+1
                            task_call_data[task_name][import_time][callout_date][
                                recall_strategy
                            ][
                                "connected_total"
                            ] += connected_num  # 接通量+0或+1
                            task_call_data[task_name][import_time][callout_date][
                                recall_strategy
                            ][
                                "duration_total"
                            ] += dialog_duration_min  # 通话分钟数累加
                            task_call_data[task_name][import_time][callout_date][
                                recall_strategy
                            ][
                                "a_intent_total"
                            ] += a_intent_num  # a意向数累加
                            task_call_data[task_name][import_time][callout_date][
                                recall_strategy
                            ][
                                "b_intent_total"
                            ] += b_intent_num  # b意向数累加
                            task_call_data[task_name][import_time][callout_date][
                                recall_strategy
                            ][
                                "prologue_total"
                            ] += prologue_num  # 开场白阶段挂断累加
                            task_call_data[task_name][import_time][callout_date][
                                recall_strategy
                            ][
                                "retention_phase_total"
                            ] += retention_phase_num  # 挽留阶段挂断总数累加
                            task_call_data[task_name][import_time][callout_date][
                                recall_strategy
                            ][
                                "bootstrap_phase_main_total"
                            ] += bootstrap_phase_main_num  # 导阶段(主流程)挂断数累加
                            # 引导阶段(挽留)挂断数累加
                            task_call_data[task_name][import_time][callout_date][
                                recall_strategy
                            ][
                                "bootstrap_phase_detainment_total"
                            ] += bootstrap_phase_detainment_num
                            task_call_data[task_name][import_time][callout_date][
                                recall_strategy
                            ][
                                "success_total"
                            ] += success_num  # 走到成功节点挂断总数累加
        logging.info(f"得到蚂蚁拨打数据分析数据：\n{data2beautify(task_call_data)}")
        return task_call_data

    def export(self):
        excel_title = [
            "外呼日期",
            "外呼任务",
            "蚂蚁触达ID",
            "追一taskId",
            "产品_策略_链路_话术版本",
            "蚂蚁推送量",
            "外呼量",
            "接通量",
            "当天累计接通率（1+1）",
            "A意向数",
            "B意向数",
            "AB意向数",
            "AB意向率",
            "AI计费分钟数",
            "备注",
            "重呼策略",
            "自动外呼设置时间",
            "导入时间",
            "开场白阶段挂断占比",
            "挽留阶段挂断占比",
            "引导阶段(主流程)挂断占比",
            "引导阶段(挽留)挂断占比",
            "成功阶段挂断占比",
        ]
        excel_data = list()
        task_call_data = self.analysis_task_call_data()
        if task_call_data:
            for task_name, task_info in task_call_data.items():
                for import_time, batch_info in task_info.items():
                    for call_date, call_date_info in batch_info.items():
                        for (
                            recall_strategy,
                            recall_strategy_info,
                        ) in call_date_info.items():
                            task_id = recall_strategy_info.get("task_id")
                            ant_push_total = recall_strategy_info.get(
                                "ant_push_total"
                            )  # 蚂蚁推送量
                            callout_total = recall_strategy_info.get(
                                "callout_total"
                            )  # 外呼量
                            connected_total = recall_strategy_info.get(
                                "connected_total"
                            )  # 接通量
                            connected_rate = calc_percent(
                                connected_total, callout_total
                            )  # 接通率
                            duration_total = recall_strategy_info.get(
                                "duration_total"
                            )  # 计费分钟数
                            a_intent_total = recall_strategy_info.get(
                                "a_intent_total"
                            )  # a意向数
                            b_intent_total = recall_strategy_info.get(
                                "b_intent_total"
                            )  # b意向数
                            ab_intent_total = (
                                a_intent_total + b_intent_total
                            )  # ab意向总数
                            ab_intent_rate = calc_percent(
                                ab_intent_total, connected_total
                            )  # ab意向率
                            prologue_total = recall_strategy_info.get("prologue_total")
                            prologue_rate = calc_percent(
                                prologue_total, connected_total
                            )  # 开场白挂断占比
                            retention_phase_total = recall_strategy_info.get(
                                "retention_phase_total"
                            )
                            retention_phase_rate = calc_percent(
                                retention_phase_total, connected_total
                            )  # 挽留挂断占比
                            bootstrap_phase_main_total = recall_strategy_info.get(
                                "bootstrap_phase_main_total"
                            )
                            bootstrap_phase_main_rate = calc_percent(
                                bootstrap_phase_main_total, connected_total
                            )  # 引导阶段（主流程）挂断占比
                            bootstrap_phase_detainment_total = recall_strategy_info.get(
                                "bootstrap_phase_detainment_total"
                            )
                            bootstrap_phase_detainment_rate = calc_percent(
                                bootstrap_phase_detainment_total, connected_total
                            )  # 引导阶段（挽留）挂断占比
                            success_total = recall_strategy_info.get("success_total")
                            success_rate = calc_percent(
                                success_total, connected_total
                            )  # 成功节点挂断占比
                            excel_data.append(
                                [
                                    call_date,
                                    task_name,
                                    "",
                                    task_id,
                                    "",
                                    ant_push_total,
                                    callout_total,
                                    connected_total,
                                    connected_rate,
                                    a_intent_total,
                                    b_intent_total,
                                    ab_intent_total,
                                    ab_intent_rate,
                                    duration_total,
                                    "",
                                    recall_strategy,
                                    "10:00-12:00，14:00-18:00",
                                    import_time,
                                    prologue_rate,
                                    retention_phase_rate,
                                    bootstrap_phase_main_rate,
                                    bootstrap_phase_detainment_rate,
                                    success_rate,
                                ]
                            )
            sheet_infos = [["统计数据", excel_title, excel_data]]
            file_name = f"{self.business}_{self.data_type}"
            excel_name = write_excel(sheet_infos, excel_save_dir, file_name, True)
            return {"code": 0, "excel_names": [excel_name], "msg": None}
        else:
            msg = (
                f"⚠️ <font color='red'>**{self.business}**</font>的<font color='green'>{self.data_type}</font>导出失败。"
                f"原因：\n<font color='blue'>在{self.start_time}至{self.end_time}没有查询到{self.call_type}数据！</font>"
            )
            logging.warning(msg)
            return {"code": 1, "excel_names": [], "msg": msg}


if __name__ == "__main__":
    client_data = {
        "target_datas": [],
        "data_date": "202505",
        "company_id": 1000,
        "business": "call",
        "business_id": 1000,
        "data_type": "每日任务拨打概况(欧派)",
        "task_type": "活跃任务",
        "call_type": "呼出",
        "start_time": "2025-05-22 00:00:00",
        "end_time": "2025-05-22 23:59:59",
    }
    export_class = ExportAntDataAnalysis(client_data)
    export_class.handled_data()
